////////////////////////////////////////////////////////////////////////////////
//(c) Intelliquip, Inc. 2001
////////////////////////////////////////////////////////////////////////////////
//$Log:
// 32   Version 10.0 (Current View)1.31        5/19/2011 10:19:08 AM  Jeff
//      Heigl      IDD#09827: removing roundtrip to RedirectConfig servlet 
// 31   Version 10.0 (Current View)1.30        5/16/2011 11:36:36 AM  Jeff
//      Heigl      IDD#09827: eliminate redirect to breakoutOfFrames.jsp
// 30   Version 10.0 (Current View)1.29        5/10/2011 11:55:46 AM  Jeff
//      Heigl      IDD#09827: Selector to Configurator latency optimization
// 29   Version 10.0 (Current View)1.28        3/7/2011 3:32:20 PM    Jeff
//      Heigl      IDD#09452: multiple conditions speed criteria
// 28   Version 10.0 (Current View)1.27        3/1/2011 10:03:19 AM   Stephen
//      Kish    IDD#08949: Refactoring appRootURL to either user or server
// 27   Version 10.0 (Current View)1.26        11/4/2010 10:25:07 AM  Jeff
//      Heigl      IDD#08939: Selector - KB support for preferred operating
//      range
// 26   Version 10.0 (Current View)1.25        8/3/2010 3:58:33 PM    Stephen
//      Kish    IDD#8949: Refactoring appRootFile and getServerRoot
// 25   Version 10.0 (Current View)1.24        12/16/2009 9:58:12 AM  Jeff
//      Heigl      IDD#8331: selector jquery cleanup
// 24   Version 10.0 (Current View)1.23        12/15/2009 5:43:49 PM  Jeff
//      Heigl      IDD#8333: serverRootURL and userServerRootURL cleanup
// 23   Version 10.0 (Current View)1.22        10/19/2009 5:52:47 PM  Jeff
//      Heigl      IDD#8193: gas constituents normalize button
// 22   Version 10.0 (Current View)1.21        10/14/2009 3:10:26 PM  Jeff
//      Heigl      IDD#8193: infrastructure for gas constituents popup page
// 21   Version 10.0 (Current View)1.20        10/13/2009 3:53:49 PM  Jeff
//      Heigl      IDD#8193: infrastructure for compressor datasheet pdf
// 20   Version 10.0 (Current View)1.19        6/22/2009 12:05:23 PM  Jeff
//      Heigl      IDD#7911: compressor cos page and common xml impl
// 19   Version 10.0 (Current View)1.18        1/26/2009 11:10:33 AM  Jeff
//      Heigl      IDD#7284: multiple conditions curve, initial implementation
// 18   Version 10.0 (Current View)1.17        10/28/2008 3:01:25 PM  Hai Hoang
//            IDD#7279: Multiple conditions page GUI infrastructure
// 17   Version 10.0 (Current View)1.16        9/22/2008 12:29:25 PM  Hai Hoang
//            IDD#7180: persisting systemCurve settings
// 16   Version 10.0 (Current View)1.15        2/27/2008 5:19:10 PM   Jeff
//      Heigl      IDD#6620: view all instances working for head loss with
//      single fitting
// 15   Version 10.0 (Current View)1.14        2/8/2008 4:07:28 PM    Jeff
//      Heigl      IDD#6580: cleanup to prepare for the bug fix for the
//      preferences submit redirecting to system number 1
// 14   Version 10.0 (Current View)1.13        1/29/2008 3:56:54 PM   Jeff
//      Heigl      IDD#5830: code cleanup - javascript and urls
// 13   Version 10.0 (Current View)1.12        1/23/2008 3:49:45 PM   Jeff
//      Heigl      IDD#6526: creating a sample head loss pdf and getting it to
//      work through the UI
// 12   Version 10.0 (Current View)1.11        1/23/2008 10:59:54 AM  Jeff
//      Heigl      IDD#6526: setting up the infrastructure to support a head
//      loss PDF
// 11   Version 10.0 (Current View)1.10        1/17/2008 2:37:38 PM   Jeff
//      Heigl      IDD#5830: using the CustomDataServlet to load the head loss
//      system type image
// 10   Version 10.0 (Current View)1.9         1/17/2008 1:58:36 PM   Jeff
//      Heigl      IDD#6514: Support CustomDataServlet within Selector
// 9    Version 10.0 (Current View)1.8         12/3/2007 5:50:22 PM   Hai Hoang
//            IDD#6362:  GUI interactions
// 8    Version 10.0 (Current View)1.7         12/3/2007 10:38:04 AM  Hai Hoang
//            IDD#6362: GUI navigations
// 7    Version 10.0 (Current View)1.6         11/30/2007 9:47:28 AM  Hai Hoang
//            IDD#6362: GUI update
// 6    Version 10.0 (Current View)1.5         11/14/2007 3:59:49 PM  Vishnu
//      Akkaraju idd #6378 -- added a new method in urlbuilder.java
// 5    Version 10.0 (Current View)1.4         11/9/2007 1:05:03 PM   Jeff
//      Heigl      IDD#5830: java objects checkin, pt7
// 4    Version 10.0 (Current View)1.3         10/24/2007 5:40:26 PM  Jeff
//      Heigl      IDD#5830: refactoring
// 3    Version 10.0 (Current View)1.2         10/24/2007 4:30:07 PM  Jeff
//      Heigl      IDD#5830: UI structuring to support the head loss popup
//      windows
// 2    Version 10.0 (Current View)1.1         10/23/2007 5:26:31 PM  Jeff
//      Heigl      IDD#5830: UI structuring and prep for head loss module
// 1    Version 10.0 (Current View)1.0         10/23/2007 5:15:06 PM  Jeff
//      Heigl      
//$
//$NoKeywords$
////////////////////////////////////////////////////////////////////////////////
package com.intelliquip.hydraulicselection.control.web;

import java.io.File;
import java.io.FileNotFoundException;
import java.net.URL;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;

import com.intelliquip.constants.PdfPage;
import com.intelliquip.core.Applications;
import com.intelliquip.core.customdata.CustomDataConstants;
import com.intelliquip.core.customdata.CustomDataUrl;
import com.intelliquip.core.customdata.CustomDataUrlParams;
import com.intelliquip.core.customdata.CustomDataValidator;
import com.intelliquip.hydraulicselection.Application;
import com.intelliquip.hydraulicselection.SelectorProperties;
import com.intelliquip.hydraulicselection.UserPreferences;
import com.intelliquip.hydraulicselection.productline.web.ProductLineWebImpl;
import com.intelliquip.labels.PageLanguageUI;
import com.intelliquip.util.ServletUtils;
import com.intelliquip.util.StringUtils;
import com.intelliquip.util.UrlPathAppender;

public class UrlBuilder {

	/**
	 * Logger for this class
	 */
	private static final Logger log = Logger.getLogger(UrlBuilder.class);

	private final String contextPath;
	private final String servletPath;
	private final String scheme_serverName_port;
	private final String dynamicID;
	private final String partyCurvePrefsParams;
	private final String orgFolderHome;
	/**
	 * This specifies the page to which we should return when a popup window is submit (in either party or selector)
	 */
	private String returnURL;

	/**
	 * Constructor
	 * @param request
	 * @param userPreferences
	 * @param currentURL - current screen's url (found in {@link ScreenNames}) used to construct the {@link #returnURL}.
	 * 						However for popup submit JSPs this must be set explicitly using {@link #setReturnURL(String)} from the result of {@link NavigationFlags#processCurrentScreen()}
	 */
	public UrlBuilder(HttpServletRequest request, UserPreferences userPreferences, String currentURL) {
		this.orgFolderHome = userPreferences.getOrgFolderHome();
		this.dynamicID = userPreferences.getUser().getDynamicID();
		this.partyCurvePrefsParams = initPartyCurvePrefsParams(userPreferences);

		/*--------------------------------------------------------
		 * START - initialize variables based on the request
		 * (if modified, then also change the other constructor(s)
		 ---------------------------------------------------------*/
		this.contextPath = request.getContextPath();
		String servletPathTemp = (String) request.getAttribute("servletPath");
		if (servletPathTemp == null) {
			servletPath = Applications.getSelectorServletPath();
		} else {
			this.servletPath = servletPathTemp;
		}
		this.scheme_serverName_port = ServletUtils.getScheme_ServerName_Port(request);
		/*-------------------------------------------------
		 * END - initialize variables based on the request
		 --------------------------------------------------*/


		/*-----------------------------------------------------
		 * START - variables needed only with this constructor
		 ------------------------------------------------------*/
		if (!ScreenNames.isValidUrl(currentURL)) {
			log.warn("Invalid url specified as currentURL: \"" + currentURL + "\"");
		}
		/*if(currentURL.indexOf('?') > -1) {
			log.warn("The currentURL should not contain '?' symbol, it should only use '&' for GET parameters: \"" + currentURL + "\"");
		}*/
		setReturnURL(scheme_serverName_port + contextPath + servletPath + currentURL);
		/*-----------------------------------------------------
		 * END - variables needed only with this constructor
		 ------------------------------------------------------*/
	}

	/**
	 * Only use this constructor if you definately do not have the request object.
	 * This can suffer from a bug, because urls will be constructed using {@link SelectorProperties#getServerRootURL()}, which is http://localhost
	 *
	 */
	public UrlBuilder(UserPreferences userPreferences) {
		this.orgFolderHome = userPreferences.getOrgFolderHome();
		this.dynamicID = userPreferences.getUser().getDynamicID();
		this.partyCurvePrefsParams = initPartyCurvePrefsParams(userPreferences);


		this.contextPath = Applications.getSelectorContextPath();
		this.servletPath = Applications.getSelectorServletPath();
		this.scheme_serverName_port = SelectorProperties.getServerRootURL();
	}

	private String initPartyCurvePrefsParams(UserPreferences userPreferences) {
		return "&atmosphere=" + userPreferences.getOperatingConditions().getAtmosphere() +
				"&fluidDensity=" + userPreferences.getOperatingConditions().getFluidDensity() +
				"&preferredOperatingRegionFromSelConfig="+String.valueOf(userPreferences.isPreferredOperatingRegionFromSelConfig());
	}

	/**
	 * specialization of {@link #buildUrl(String, boolean, boolean, String[][])}.
	 * Passes in:isPopupWindow=false, isPDF=false, urlGetParams=null.
	 * @param servletUrl
	 * @return String
	 */
	public String buildUrl(String servletUrl) {
		return buildUrl(servletUrl, false, false, null);
	}

	/**
	 * specialization of {@link #buildUrl(String, boolean, boolean, String[][])}.
	 * Passes in: isPDF=false, urlGetParams=null.
	 * @param servletUrl
	 * @param isPopupWindow - true if this is a popup that DOES NOT USE the {@link PageFactory} design
	 * @return String
	 */
	public String buildUrl(String servletUrl, boolean isPopupWindow) {
		return buildUrl(servletUrl, isPopupWindow, false, null);
	}

	/**
	 * Build a complete url.
	 * This can handle building urls that point to the Party Management app, and will append the necessary parameters.
	 *
	 * @param servletUrl - a url from {@link ScreenNames}, if it has a query string then it will be appended to the returned url
	 * @param isPopupWindow - setting this to true will cause a direct link to the JSP to be created and returned.
	 * 						Must NOT USE the {@link PageFactory} design, in that case just build a normal url.
	 * @param isPDF - set to true if the url is for a PDF
	 * @return - complete url including necessary parameters, or null if theres a failure constructing the url
	 */
	public String buildUrl(String servletUrl, boolean isPopupWindow, boolean isPDF, String[][] urlGetParams) {
		String url = null;
		try {
			if (ScreenNames.isValidUrl(servletUrl)) {

				String jsp = ScreenNames.getJspByUrl(servletUrl);
				String queryString = ServletUtils.getQueryStringFromUrl(servletUrl);  //append existing parameters to returnUrl

				if (ScreenNames.isPartyPreferencesURL(servletUrl)) {
					String baseUrl = contextPath + servletUrl;
					url = ServletUtils.addParameterToURL(baseUrl, "UID", dynamicID) + "&returnURL=" + getReturnURL() + partyCurvePrefsParams;
				} else if(isPDF) {
					//does not go thru MainServlet (so we dont need servletPath)
					url = contextPath + servletUrl;
				} else if (isPopupWindow) {
					if(DisplayController.isSupportedByDisplayServlet(servletUrl)) {
						//will use the displayServlet
						String servletUrlWithoutQueryString = ServletUtils.removeQueryStringFromUrl(servletUrl);
						url = contextPath + ScreenNames.DISPLAY_SERVLET_URL + "?selectedURL="+ servletUrlWithoutQueryString + queryString.replace('?', '&');
					} else {
						// these will not go thru MainServlet, it will access the jsp directly
						String baseUrl = contextPath + UrlBuilder.getJspRelativePath(jsp) + "/" + jsp + queryString;
						url = ServletUtils.addParameterToURL(baseUrl, "returnURL", getReturnURL());
					}
				} else if (ScreenNames.OUTPUT_GRAPH_URL.equals(servletUrl)) {
					//special case, the output graph must not go through MainServlet (/App)
					url = contextPath + servletUrl;
				} else {
					// this will go thru the MainServlet and use the servletUrl (which already contains the query string)
					url = contextPath + servletPath + servletUrl;
				}

			} else {
				throw new Exception("The specified url is not in " + ScreenNames.class.getSimpleName() + " \"" + servletUrl + "\"");
			}
		} catch (Exception e) {
			log.error("", e);
		}

		return ServletUtils.addParametersToURL(url, urlGetParams);
	}

	/**
	 * prevent NullPointerException by doing a String.valueOf(url) instead of url.toString()
	 * @param url
	 * @return String
	 */
	private String urlToString(URL url) {
		return String.valueOf(url);
	}

	public String getTargetPath() {
		return scheme_serverName_port + contextPath + servletPath;
	}

	/**
	 * Hit the disk to find the jsp's relative path.
	 * This would not be necessary if we placed all JSPs in the same folder (and it should be under WEB-INF).
	 *
	 * @param jsp
	 * @return - the path relative to the selector's contextPath. If its in the root, then an empty String is returned.
	 * @throws FileNotFoundException - when the jsp cannot be located
	 */
	private static String getJspRelativePath(String jsp) throws FileNotFoundException {
		String retVal = null;

		String realPath = Application.getRealPath();
		if (new File(realPath + "/" + jsp).exists()) {
			// test if its in the web_source root
			retVal = "";
		} else if (new File(realPath + "/intelliquip/" + jsp).exists()) {
			// test if its in the intelliquip folder
			retVal = "/intelliquip";
		} else {
			throw new FileNotFoundException("Cannot locate the jsp \""+jsp+"\"");
		}

		return retVal;
	}

	public String getReturnURL() {
		return returnURL;
	}

	/**
	 * For popup submit JSPs this must be set using the result of {@link NavigationFlags#processCurrentScreen()}.
	 * For all other pages this is not necessary.
	 *
	 * @param returnURL - complete url
	 */
	public void setReturnURL(String returnURL) {
		this.returnURL = returnURL;
	}

	/**
	 * Used for images in CustomData/<org>/ConfigData/<configBaseDir>/images/template/ location.
	 * The URL is not yet complete, it only points to the folder.
	 * @return null if not valid
	 */
	public String buildUrl_headLossConfigImages(String fileName) {
		String relativePath = CustomDataUrl.getConfigDataRelativePath(CustomDataConstants.HEADLOSSCONFIG_CONFIGBASEDIR, CustomDataConstants.HEADLOSSCONFIG_IMAGES_SUBDIR);
		relativePath += fileName;

		CustomDataUrl url = getCustomDataURL(new CustomDataUrlParams(orgFolderHome, relativePath, dynamicID), true);
		return url.getUrl();
	}

	/**
	 * retrieve the CustomData URL with its GET parameters filled out
	 * @param params - filePath has the relative location to the file (do not include the orgFolderHome)
	 * @return {@link CustomDataUrl}, never null
	 */
	public CustomDataUrl getCustomDataURL(CustomDataUrlParams params, boolean doDiskCheck) {
		CustomDataUrl url = new CustomDataUrl(SelectorProperties.getCustomDataPath(),scheme_serverName_port,contextPath,params);
		if(doDiskCheck && !CustomDataValidator.validateWithDiskCheck(url)) {
			log.warn("Cannot locate the CustomData file: \""+CustomDataUrl.getUrl(url)+"\"");
		}
		return url;
	}

	/**
	 * @param servletUrl - pdf servlet url (some are not matching between web.xml and {@link ScreenNames}, so use web.xml for now)
	 * @param pdfPage
	 * @return url
	 */
	public String buildUrl_pdf(String servletUrl, PdfPage pdfPage) {
		String[][] getParams = new String[][] {{"screenIDfop",String.valueOf(pdfPage.getPdfID())}, {"intellequip","ieq.pdf"}};
		return buildUrl(servletUrl, true, true, getParams);
	}

	public String buildUrl(ScreenNames.Javascript screenName) {
		URL url = null;
		try {
			String rootUrl;
			if(screenName.isHostedInParty()) {
				rootUrl = getPartyUserAppRootUrl();
			} else {
				rootUrl = scheme_serverName_port + contextPath;
			}
			url = new URL(rootUrl + screenName.relativeDir + "/" + screenName.fileName);
		} catch (Exception e) {
			log.error("", e);
		}
		return urlToString(url);
	}

	private String getPartyUserAppRootUrl() {
		return Applications.getPartyUserAppRootURL(scheme_serverName_port);
	}

	/**
	 * Returns the serverRootURL based on the request or from SelectorProperties.xml depending on the
	 * constructor of UrlBuilder used.
	 *
	 * @return String
	 */
	public String getServerRootURL() {
		return scheme_serverName_port;
	}

	/**
	 * get the context path with a starting slash but without an ending slash (i.e. /IEQ_HydSel/HydSel_JSP)
	 */
	public String getContextPath() {
		return contextPath;
	}

	/**
	 * get the root images path, NOT the org images path which is obtained from {@link UserPreferences#getOrgImagesPath()}
	 */
	public String getImagesPath() {
		return getContextPath() + "/images/";
	}

	public String buildUrlToJSP(String servletUrl) {
		return buildUrl(servletUrl, true);
	}
}
